﻿#ifdef _WIN32
#include "windows_defines.h"
#endif

#include "../../../../../../unittest/framework/unittest.hh"

#include "guildservicebuilding.enum.h"

#include "RegisterArg_struct.h"
#include "RegisterRes_struct.h"
#include "UnregisterNtfData_struct.h"
#include "BuildingUpgradeArg_struct.h"
#include "BuildingUpgradeRes_struct.h"

#include "box/service_box.hh"
#include "box/service_context.hh"
#include "detail/service_context_impl.hh"

#include "guild_service_basic_context.h"
#include "guild_service_query_context.h"
#include "guild_service_building_context.h"
#include "guild_service_auth_context.h"

#include "protobuf/guildservicebasic.service.pb.h"
#include "protobuf/guildservicequery.service.pb.h"
#include "protobuf/guildservicebuilding.service.pb.h"
#include "util/time_util.hh"
#include "rpc_root.h"
#include "guild/guild.h"

FIXTURE_BEGIN(test_guild_service_building)

std::array<uint64_t, 10> role_uuid_list;
std::array<uint64_t, 10> guild_id_list;
std::array<uint64_t, 10> guild_red_envelope_uid_list;
std::array<guild_service::token_type, 10> token_list;

bool is_auto_approval = true;

const char* argv[] = {"test_building", "--config=test_building_box.cfg"};
kratos::service::ServiceBox* box = new kratos::service::ServiceBox();
uint32_t test_round = 0;

SETUP([&]() {
  std::cout << "\n==================================== "
            << "Round " << test_round++
            << " ====================================\n";
  srand(static_cast<unsigned int>(time(nullptr)));

  for (auto& it : role_uuid_list) {
    it = static_cast<uint64_t>(rand() % 5000000 + 1);
  }

  guild_id_list.fill(0ull);
  guild_red_envelope_uid_list.fill(0ull);

  box->start(2, argv);
})

/// 服务开始
#define BOX_SERVICE_START()                                                       \
  auto context_imp_ptr =                                                      \
      kratos::make_unique_pool_ptr<kratos::service::ServiceContextImpl>(box); \
  auto context_ptr =                                                          \
      dynamic_cast<kratos::service::ServiceContext*>(context_imp_ptr.get());  \
  ASSERT_TRUE(guild_service::GuildServiceBasicContext::Init(context_ptr));    \
  ASSERT_TRUE(guild_service::GuildServiceQueryContext::Init(context_ptr));    \
  ASSERT_TRUE(guild_service::GuildServiceBuildingContext::Init(context_ptr));  \
  ASSERT_TRUE(guild_service::GuildServiceAuthContext::Init(context_ptr));

/// 服务等待
#define BOX_SERVICE_WAIT(ms)                                          \
  {                                                               \
    auto start = kratos::util::get_os_time_millionsecond();       \
    while (true) {                                                \
      auto now = kratos::util::get_os_time_millionsecond();       \
      if (now - start > ms) {                                     \
        break;                                                    \
      }                                                           \
      std::this_thread::sleep_for(std::chrono::milliseconds(10)); \
    }                                                             \
  }

/// 服务运行
#define BOX_SERVICE_RUN(ms)                                           \
  {                                                               \
    auto start = kratos::util::get_os_time_millionsecond();       \
    while (true) {                                                \
      guild_service::GuildServiceBasicContext::Tick(              \
          kratos::util::get_os_time_millionsecond());             \
      guild_service::GuildServiceQueryContext::Tick(              \
          kratos::util::get_os_time_millionsecond());             \
      guild_service::GuildServiceBuildingContext::Tick(            \
          kratos::util::get_os_time_millionsecond());             \
      guild_service::GuildServiceAuthContext::Tick(               \
          kratos::util::get_os_time_millionsecond());             \
      auto now = kratos::util::get_os_time_millionsecond();       \
      if (now - start > ms) {                                     \
        break;                                                    \
      }                                                           \
      std::this_thread::sleep_for(std::chrono::milliseconds(10)); \
    }                                                             \
  }

/// 服务停止
#define BOX_SERVICE_STOP(ms)                                          \
  {                                                                   \
    BOX_SERVICE_RUN(ms)                                               \
    ASSERT_TRUE(guild_service::GuildServiceBasicContext::Uninit());   \
    ASSERT_TRUE(guild_service::GuildServiceQueryContext::Uninit());   \
    ASSERT_TRUE(guild_service::GuildServiceBuildingContext::Uninit()); \
    ASSERT_TRUE(guild_service::GuildServiceAuthContext::Uninit());    \
  }

CASE(TestGuildServiceBuilding0) {
  BOX_SERVICE_START()
  co(
    std::cout << '\n'; for (int i = 0; i < 4; ++i) {
    RegisterArg arg;
    arg.account = guild_service::kTestAccountList[i];
    arg.passwd = guild_service::kTestPasswdList[i];
    rpc::StubCallPtr call = std::dynamic_pointer_cast<rpc::StubCall>(
         std::shared_ptr<rpc::StubCallImpl>(nullptr));

    std::cout << "Register"
              << "\t账号:" << arg.account << "\t密码:" << arg.passwd << '\n';

    auto res = std::make_shared<RegisterRes>();
    try {
      guild_service::GuildServiceAuthContext::Register(call, arg, res);
      {
        std::cout << "Register"
                  << "\t结果:" << static_cast<int>(res->result)
                  << "\t凭证:" << res->token
                  << "\t角色唯一id:" << res->role_uuid << '\n';
      }

      ASSERT_TRUE(res->result == guildserviceauth_cpp::ErrorCode::ERR_SUCCESS);
      ASSERT_TRUE(res->token != 0);
      ASSERT_TRUE(res->role_uuid != 0);

      token_list[i] = res->token;
      role_uuid_list[i] = res->role_uuid;
    } catch (std::exception& ex) {
      std::cerr << "Register exception &:" << ex.what() << std::endl;
    }
  }) BOX_SERVICE_STOP(2000)
}

/// 注册账号
CASE(TestGuildServiceBuilding1) {
  BOX_SERVICE_START()
  co(
      std::cout << '\n';
      BuildingUpgradeArg arg;
      arg.token = token_list[0];
      arg.building_id = 0;
      arg.level = 1;
      std::cout << "BuildingUpgrade"
                << "\t凭证:" << arg.token << '\n';

      auto res = std::make_shared<BuildingUpgradeRes>();
      rpc::StubCallPtr call = std::dynamic_pointer_cast<rpc::StubCall>(
         std::shared_ptr<rpc::StubCallImpl>(nullptr));
      try {
        guild_service::GuildServiceBuildingContext::BuildingUpgrade(call, arg, res);
        {
          std::cout << "BuildingUpgrade"
                    << "\t结果:" << static_cast<int>(res->result) << '\n';
        }
        ASSERT_TRUE(res->result == guildservicebuilding_cpp::ErrorCode::ERR_SUCCESS);
      } catch (std::exception& ex) {
        std::cerr << "BuildingUpgrade exception &:" << ex.what() << std::endl;
      }
  )
  BOX_SERVICE_STOP(500)
}

FIXTURE_END(test_guild_service_building)
